/**
 * @addtogroup FXCRT
 * @{
 */

/**
 * @file
 * @brief Process & thread 
 */

#ifndef _FXM_OPENSOURCE_

#ifndef _FX_PROCESS_H_
#define _FX_PROCESS_H_

#ifndef _FX_BASIC_H_
	#include "fx_basic.h"
#endif

#if _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_LINUX_EMBEDDED_ || _FX_OS_ == _FX_ANDROID_ || _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_
	#include <time.h>
	#include <sys/time.h>
	#include <pthread.h>
	#include <unistd.h>
#endif

//external classes
class CFX_ProcessContext;
class CFX_ThreadContext;
class CFX_ExceptionContext;

//*****************************************************************************
//* Time
//*****************************************************************************
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @name Time
 */
/*@{*/

/** @brief	Structure of system time. */
typedef struct _FX_SYSTEMTIME
{
	FX_WORD wYear;			//Year
	FX_WORD wMonth;			//Month, 1 - 12
	FX_WORD wDayOfWeek;		//Day of week, Sunday is 0, Monday is 1, ...
	FX_WORD wDay;			//Day of month, start from 1 - 31
	FX_WORD wHour;			//Hour, 0 - 23
	FX_WORD wMinute;		//Minute, 0 - 59
	FX_WORD wSecond;		//Second, 0 - 59
	FX_WORD wMilliseconds;	//Millisecond, 0 - 999
} FX_SYSTEMTIME;

/**
 * @brief	Retrieve the current system/local date and time.
 *
 * @param[in,out] pSystemTime	Pointer to a FX_SYSTEMTIME to receive the current system data and time.
 */
void		FX_Time_GetSystemTime(FX_SYSTEMTIME* pSystemTime);
void		FX_Time_GetLocalTime(FX_SYSTEMTIME* pSystemTime);
/**
 * @brief	Get the clock ticks elapsed by calling process.
 *
 * @return	Elapsed time in milliseconds.
 */
FX_DWORD	FX_Time_GetClock();
/**
 * @brief	Delay the current running for specified milliseconds.
 *
 * @param[in] dwMilliseconds	Time in milliseconds to delay.
 *
 * @return	Remained time has not elapsed, 0 if time interval expired.
 */
FX_DWORD	FX_Time_Sleep(FX_DWORD dwMilliseconds);

/*@}*/

#ifdef __cplusplus
}
#endif

//*****************************************************************************
//* Process
//*****************************************************************************
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @name Type for process ID
 */
/*@{*/

#if _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_
	typedef	pid_t		FX_PROCESSID;
#else
	typedef FX_DWORD	FX_PROCESSID;
#endif

/*@}*/

/**
 * @name Process management
 */
/*@{*/

/**
 * @brief	Initialize process.
 *
 * @remark	Application should call this function after initializes memory management.
 *			This function will prepare some global resources which are used in application.
 */
void				FX_Process_Initialize();
/**
 * @brief	Finalize process.
 *
 * @remark	Application should call this function before release memory management
 *			When application stops running.
 */
void				FX_Process_Finalize();
/**
 * @brief	Get the current process ID
 *
 * @return	The current process ID
 */
FX_PROCESSID		FX_Process_GetID();

/**
 * @brief	Get private data in the current process.
 *
 * @param[in] key	Key value to specify private data to be retrieved.
 *
 * @return	Pointer to private data, NULL if failure.
 */
FX_LPVOID			FX_Process_GetPrivateData(FX_LPVOID key);
/**
 * @brief	Set private data in the current process.
 *
 * @param[in] key		Key value to specify private data to be set.
 * @param[in] data		Pointer to private data.
 * @param[in] callback	Callback function address which is used to free private data,
 *						pass NULL if need no additional process to free private data.
 */
void				FX_Process_SetPrivateData(FX_LPVOID key, FX_LPVOID data, PD_CALLBACK_FREEDATA callback);
/**
 * @brief	Remove private data in the current process.
 *
 * @param[in] key	Key value to specify private data to be removed.
 */
void				FX_Process_RemovePrivateData(FX_LPVOID key);

/**
 * @brief	Retrieve process context.
 *
 * @return	Returns the current process context object.
 * @remark	This function is used internally.
 */
CFX_ProcessContext*	FX_Process_GetContext();

/*@}*/

#ifdef __cplusplus
}
#endif

//*****************************************************************************
//* Thread
//*****************************************************************************
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @name Type for thread ID
 */
/*@{*/

/** @brief	Type definition of mutex handle. */
FX_DEFINEHANDLE(FX_HTHREAD);

/*
#if _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_
	typedef pthread_t	FX_THREADID;
#else
	typedef FX_DWORD	FX_THREADID;
#endif
*/

/*@}*/

/**
 * @name Flags for thread priorities
 */
/*@{*/

/** @brief	Lowest priority. */
#define FX_THREADPRIORITY_Lowest	-2
/** @brief	Lower priority. */
#define FX_THREADPRIORITY_Lower		-1
/** @brief	Normal priority. */
#define FX_THREADPRIORITY_Normal	0
/** @brief	Higher priority. */
#define FX_THREADPRIORITY_Higher	1
/** @brief	Highest priority. */
#define FX_THREADPRIORITY_Highest	2

/*@}*/

/**
 * @name Flags for thread priorities
 */
/*@{*/

/**
 * @brief	Callback function of thread procedure.
 *
 * param[in] param	Thread parameter transfered when create thread.
 */
typedef void (*FX_CALLBACK_ThreadProc)(FX_LPVOID param);

/*@}*/

/**
 * @name Thread handler
 */
/*@{*/

/**
 * @brief	Thread handler for application extension.
 *
 * @remark	This feature is disabled under single-thread mode or _FPDFAPI_MT_ isn't defined.
 */
typedef struct _FX_THREADHANDLER
{
	/** @brief	Pointer to user data. */
	FX_LPVOID		pUserData;

	/**
	 * @brief	Callback function to create a thread.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 * @param[in] nPriority		Thread priority, set to 0 at default.
	 * @param[in] szStack		Stack size for thread, set to 0 at default.
	 * @param[in] lpfThreadProc	Function address for thread procedure.
	 * @param[in] param			User parameters passed to thread procedure.
	 *
	 * @return	Handle of thread, NULL if failure.
	 */
	FX_HTHREAD		(*CreateThread)(FX_LPVOID pUserData, FX_INT32 nPriority, size_t szStack, FX_CALLBACK_ThreadProc lpfThreadProc, FX_LPVOID param);
	/**
	 * @brief	Callback function to exit from the current thread.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 *
	 * @return	TRUE if exits successfully, or FALSE for failure.
	 */
	FX_BOOL			(*ExitThread)(FX_LPVOID pUserData);
	/**
	 * @brief	Callback function to get handle of the current thread.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 *
	 * @return	Thread handle, NULL if error occurs.
	 */
	FX_HTHREAD		(*GetCurrentThread)(FX_LPVOID pUserData);
	/**
	 * @brief	Callback function to change CPU time to another thread.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 *
	 * @remark	Call this function to alternate to another thread if caller wants to break
	 *			the current thread running. Calling thread will be awoken in next thread polling.
	 */
	void			(*Yield)(FX_LPVOID pUserData);
	/**
	 * @brief	Callback function to get thread priority.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 * @param[in] hThread		Thread handle specifies a thread to retreive its priority.
	 *
	 * @return	Thread priority code, refers to FX_THREADPRIORITY_XXX macros.
	 */
	FX_INT32		(*GetThreadPriority)(FX_LPVOID pUserData, FX_HTHREAD hThread);
	/**
	 * @brief	Callback function to set thread priority.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 * @param[in] hThread		Thread handle specifies a thread to set its priority.
	 * @param[in] nPriority		Thread priority code.
	 */
	void			(*SetThreadPriority)(FX_LPVOID pUserData, FX_HTHREAD hThread, FX_INT32 nPriority);
	/**
	 * @brief	Wait for termination of a single thread.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 * @param[in] hThread		Thread handle specifies a thread to wait.
	 *
	 * @return	0 means thread terminates successfully, other value means failure.
	 */
	FX_INT32		(*WaitForSingleThread)(FX_LPVOID pUserData, FX_HTHREAD hThread);
	/**
	 * @brief	Wait for termination of multiple threads.
	 *
	 * @param[in] pUserData		Pointer to user data.
	 * @param[in] pThreads		Pointer to array of thread handles.
	 * @param[in] nCount		Number of threads in array.
	 *
	 * @return	0 means all threads terminates successfully, other value means failure.
	 */
	FX_INT32		(*WaitForMultipleThreads)(FX_LPVOID pUserData, const FX_HTHREAD* pThreads, FX_INT32 nCount);
}FX_THREADHANDLER;

/**
 * @brief	Get the current thread handler.
 *
 * @return	Returns the current thread handler, NULL if doesn't set.
 * @remark	This function returns NULL always under single-thread mode or _FPDFAPI_MT_ isn't defined.
 */
FX_THREADHANDLER*		FX_Thread_GetHandler();
/**
 * @brief	Set the current thread handler.
 *
 * @param[in] pThreadHandler	Pointer to external thread handler.
 *
 * @remark	This function is disabled under single-thread mode or _FPDFAPI_MT_ isn't defined.
 */
void					FX_Thread_SetHandler(FX_THREADHANDLER* pThreadHandler);

/*@}*/

/**
 * @name Thread functions
 */
/*@{*/

/**
 * @brief	Create a new thread.
 *
 * @param[in] nPriority		Thread priority.
 * @param[in] szStack		Stack size of thread, set to 0 for default stack size.
 * @param[in] threadProc	Thread callback function.
 * @param[in] param			Parameter passed to thread procedure.
 *
 * @return	Thread handle, NULL if failure.
 */
FX_HTHREAD				FX_Thread_Create(FX_INT32 nPriority, size_t szStack, FX_CALLBACK_ThreadProc threadProc, FX_LPVOID param);

/**
 * @brief	Exit from the current thread.
 */
void					FX_Thread_Exit();

/**
 * @brief	Get the current thread handle.
 *
 * @return	The current thread handle, NULL if failure.
 */
FX_HTHREAD				FX_Thread_GetHandle();

/**
 * @brief	Yield the processor to another thread.
 */
void					FX_Thread_Yield();

/**
 * @brief	Get the last error code in the current thread.
 *
 * @return	The last error code.
 */
FX_INT32				FX_Thread_GetLastError();
/**
 * @brief	Set the last error code in the current thread.
 *
 * @param[in] nErr	The last error code to be set.
 */
void					FX_Thread_SetLastError(FX_INT32 nErr);

/**
 * @brief	Get private data in the current thread.
 *
 * @param[in] key	Key value to specify private data to be retrieved.
 *
 * @return	Pointer to private data, NULL if failure.
 */
FX_LPVOID				FX_Thread_GetPrivateData(FX_LPVOID key);
/**
 * @brief	Set private data in the current thread.
 *
 * @param[in] key		Key value to specify private data to be set.
 * @param[in] data		Pointer to private data.
 * @param[in] callback	Callback function address which is used to free private data,
 *						pass NULL if need no additional process to free private data.
 */
void					FX_Thread_SetPrivateData(FX_LPVOID key, FX_LPVOID data, PD_CALLBACK_FREEDATA callback);
/**
 * @brief	Remove private data in the current thread.
 *
 * @param[in] key	Key value to specify private data to be removed.
 */
void					FX_Thread_RemovePrivateData(FX_LPVOID key);

/**
 * @brief	Get thread priority.
 *
 * @param[in] hThread		Thread handle specifies a thread to retrieve its priority.
 *
 * @return	Priority code of thread.
 */
FX_INT32				FX_Thread_GetPriority(FX_HTHREAD hThread);
/**
 * @brief	Set thread priority.
 *
 * @param[in] hThread		Thread handle specifies a thread to change its priority.
 * @param[in] nPriority		Thread priority code.
 */
void					FX_Thread_SetPriority(FX_HTHREAD hThread, FX_INT32 nPriority);

/**
 * @brief	Wait for termination of a single thread.
 *
 * @param[in] hThread		Thread handle specifies a thread to wait.
 *
 * @return	0 means thread terminates successfully, other value means failure.
 */
FX_INT32				FX_Thread_WaitForSingleThread(FX_HTHREAD hThread);
/**
 * @brief	Wait for termination of multiple threads.
 *
 * @param[in] pThreads		Pointer to array of thread handles.
 * @param[in] nCount		Number of threads in array.
 *
 * @return	0 means all threads terminates successfully, other value means failure.
 */
FX_INT32				FX_Thread_WaitForMultipleThreads(const FX_HTHREAD* pThreads, FX_INT32 nCount);

/*@}*/

/**
 * @name Context access
 */
/*@{*/

/**
 * @brief	Get the current thread context.
 *
 * @return	The current thread context, NULL if failure.
 */
CFX_ThreadContext*		FX_Thread_GetContext();

/**
 * @brief	Get the current thread exception context.
 *
 * @return	The current thread exception context, NULL if failure.
 */
CFX_ExceptionContext*	FX_Thread_GetExceptionContext();

/*@}*/

#ifdef __cplusplus
}
#endif

//*****************************************************************************
//* Cocurrency controls
//*****************************************************************************
/**
 * @name Mutex
 *
 * @remark	Mutex is disabled under single-thread mode or _FPDFAPI_MT_ isn't defined,
 *			do not call the following functions under this condition.
 *			Mutex supports recursive calls in same thread.
 */
/*@{*/

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief	Initialize a mutex.
 *
 * @param[in] pMutex	Pointer to a mutex which need to be initialized. Must be not a NULL pointer.
 *
 * @return	TRUE if mutex is successfully initialized, FALSE if fails.
 */
FX_BOOL			FX_Mutex_Initialize(FX_MUTEX* pMutex);
/**
 * @brief	Destroy a mutex.
 *
 * @param[in] pMutex	Pointer to a mutex to be destroyed. Must be not a NULL pointer.
 */
void			FX_Mutex_Destroy(FX_MUTEX* pMutex);
/**
 * @brief	Try to lock a mutex.
 *
 * @param[in] pMutex	Pointer to a mutex. Must be not a NULL pointer.
 *
 * @return	TRUE if the given mutex object is locked successfully or the current thread already owns the mutex,
 *			FALSE if another thread owns the mutex already or other error occurs.
 */
FX_BOOL			FX_Mutex_TryLock(FX_MUTEX* pMutex);
/**
 * @brief	Lock a mutex.
 *
 * @param[in] pMutex	Pointer to a mutex. Must be not a NULL pointer.
 *
 * @remark	If another thread owns the mutex when calls this function, this function won't return
 *			until the current thread obtains the ownership of the mutex.
 */
void			FX_Mutex_Lock(FX_MUTEX* pMutex);
/**
 * @brief	Unlock a mutex.
 *
 * @param[in] pMutex	Pointer to a mutex. Must be not a NULL pointer.
 */
void			FX_Mutex_Unlock(FX_MUTEX* pMutex);

#ifdef __cplusplus
}
#endif

/*@}*/

/**
 * @name Spin Lock
 *
 * @remark	Spin Lock is disabled under single-thread mode or _FPDFAPI_MT_ isn't defined,
 *			do not call the following functions under this condition.
 *			Spin Lock is a light-weight cocurrency mechanism for synchronizing access.
 *			Spin Lock doesn't support recursive calls in same thread.
 */
/*@{*/

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief	Initialize a spin lock.
 *
 * @param[in] pSpinLock		Pointer to a spin lock to be initialized.
 *
 * @return	TRUE if spin lock is successfully initialized, FALSE if fails.
 */
FX_BOOL			FX_SpinLock_Initialize(FX_SPINLOCK* pSpinLock);
/**
 * @brief	Destroy a spin lock.
 *
 * @param[in] pSpinLock		Pointer to a spin lock to be destroyed.
 */
void			FX_SpinLock_Destroy(FX_SPINLOCK* pSpinLock);
/**
 * @brief	Try to lock a spin lock.
 *
 * @param[in] pSpinLock		Pointer to a spin lock.
 *
 * @return	TRUE if the given spin lock object is locked successfully or the current thread already owns the spin lock,
 *			FALSE if another thread owns the spin lock already or other error occurs.
 */
FX_BOOL			FX_SpinLock_TryLock(FX_SPINLOCK* pSpinLock);
/**
 * @brief	Lock a spin lock.
 *
 * @param[in] pSpinLock		Pointer to a spin lock.
 *
 * @remark	If another thread owns the spin lock when calls this function, this function won't return
 *			until the current thread obtains the ownership of the spin lock.
 */
void			FX_SpinLock_Lock(FX_SPINLOCK* pSpinLock);
/**
 * @brief	Unlock a spin lock.
 *
 * @param[in] pSpinLock		Pointer to a spin lock.
 */
void			FX_SpinLock_Unlock(FX_SPINLOCK* pSpinLock);
/**
 * @brief	Determine whether specified spin lock is locked or not.
 *
 * @param[in] pSpinLock		Pointer to a spin lock.
 *
 * @return	TRUE is spin lock is locked, FALSE if it's unlocked.
 */
FX_BOOL			FX_SpinLock_IsLocked(FX_SPINLOCK* pSpinLock);

#ifdef __cplusplus
}
#endif

#ifdef _FPDFAPI_MT_

/** @brief	Spin Lock short-class. */
class CFX_SpinLock
{
public:
	CFX_SpinLock() : m_pSpinLock(NULL) {}
	CFX_SpinLock(FX_SPINLOCK* pSpinLock) : m_pSpinLock(pSpinLock) {if (m_pSpinLock) FX_SpinLock_Lock(m_pSpinLock);}
	~CFX_SpinLock() {if (m_pSpinLock) FX_SpinLock_Unlock(m_pSpinLock);}

	/** Try to lock. For separating control. */
	FX_BOOL		TryLock() {return FX_SpinLock_TryLock(m_pSpinLock);}
	/** Lock. For separating control. */
	void		Lock() {FX_SpinLock_Lock(m_pSpinLock);}
	/** Unlock. For separating control. */
	void		Unlock() {FX_SpinLock_Unlock(m_pSpinLock);}
	/** Determine whether the current spin lock is locked or not. For separating control. */
	FX_BOOL		IsLocked() {return FX_SpinLock_IsLocked(m_pSpinLock);}

	FX_SPINLOCK*	m_pSpinLock;
};

/**
 * @brief A macro means defining a lock operation with this pointer.
 * @hideinitializer
 */
#define FXMT_SPLOCK_THIS CFX_SpinLock _fx_splock((FX_SPINLOCK*)this)
/**
 * @brief A macro means defining a lock operation with a lock object.
 * @hideinitializer
 */
#define FXMT_SPLOCK_OBJ(lock) CFX_SpinLock _fx_splock(lock)

#else

/** @brief	Under non-threading mode, defines as empty implementation. */
class CFX_SpinLock {};
#define FXMT_SPLOCK_THIS
#define FXMT_SPLOCK_OBJ(lock)

#endif

/*@}*/

/**
 * @name Read-Write lock
 *
 * @remark	Read-Write Lock is disabled under single-thread mode or _FPDFAPI_MT_ isn't defined,
 *			do not call the following functions under this condition.
 */
/*@{*/

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief	Initialize a read-write lock.
 *
 * @param[in] pRWLock	Pointer to a read-write lock which need to be initialized. Must be not a NULL pointer.
 *
 * @return	TRUE if read-write lock is successfully initialized, FALSE if fails.
 */
FX_BOOL			FX_RWLock_Initialize(FX_RWLOCK* pRWLock);
/**
 * @brief	Destroy a read-write lock.
 *
 * @param[in] pRWLock	Pointer to a read-write lock to be destroyed. Must be not a NULL pointer.
 */
void			FX_RWLock_Destroy(FX_RWLOCK* pRWLock);
/**
 * @brief	Try to lock for share read.
 *
 * @param[in] pRWLock	Pointer to a read-write lock. Must be not a NULL pointer.
 *
 * @return	TRUE if the given read-write lock object is locked successfully or the current thread already owns the read-write lock,
 *			FALSE if another thread owns the read-write lock already or other error occurs.
 */
FX_BOOL			FX_RWLock_TryReadLock(FX_RWLOCK* pRWLock);
/**
 * @brief	Lock for share read.
 *
 * @param[in] pRWLock	Pointer to a read-write lock. Must be not a NULL pointer.
 *
 * @remark	If another thread owns the read-write lock when calls this function, this function won't return
 *			until the current thread obtains the ownership of the read-write lock.
 */
void			FX_RWLock_ReadLock(FX_RWLOCK* pRWLock);
/**
 * @brief	Unlock for share read.
 *
 * @param[in] pRWLock	Pointer to a read-write lock. Must be not a NULL pointer.
 */
void			FX_RWLock_ReadUnlock(FX_RWLOCK* pRWLock);
/**
 * @brief	Try to lock for exclusive write.
 *
 * @param[in] pRWLock	Pointer to a read-write lock. Must be not a NULL pointer.
 *
 * @return	TRUE if the given read-write lock object is locked successfully or the current thread already owns the read-write lock,
 *			FALSE if another thread owns the read-write lock already or other error occurs.
 */
FX_BOOL			FX_RWLock_TryWriteLock(FX_RWLOCK* pRWLock);
/**
 * @brief	Lock for exclusive write.
 *
 * @param[in] pRWLock	Pointer to a read-write lock. Must be not a NULL pointer.
 *
 * @remark	If another thread owns the read-write lock when calls this function, this function won't return
 *			until the current thread obtains the ownership of the read-write lock.
 */
void			FX_RWLock_WriteLock(FX_RWLOCK* pRWLock);
/**
 * @brief	Unlock for exclusive write.
 *
 * @param[in] pRWLock	Pointer to a read-write lock. Must be not a NULL pointer.
 */
void			FX_RWLock_WriteUnlock(FX_RWLOCK* pRWLock);

#ifdef __cplusplus
}
#endif

#ifdef _FPDFAPI_MT_

class CFX_RWLockObject : public CFX_Object
{
public:
	/** Construct a lock object. */
	CFX_RWLockObject() {FX_RWLock_Initialize(&m_Lock);}
	/** Destruct a lock object. */
	~CFX_RWLockObject() {FX_RWLock_Destroy(&m_Lock);}

	/** Try to lock. For separating control. */
	FX_BOOL		TryReadLock()	{return FX_RWLock_TryReadLock(&m_Lock);}
	/** Lock. For separating control. */
	void		ReadLock()		{FX_RWLock_ReadLock(&m_Lock);}
	/** Unlock. For separating control. */
	void		ReadUnlock()	{FX_RWLock_ReadUnlock(&m_Lock);}
	/** Try to lock. For separating control. */
	FX_BOOL		TryWriteLock()	{return FX_RWLock_TryWriteLock(&m_Lock);}
	/** Lock. For separating control. */
	void		WriteLock()		{FX_RWLock_WriteLock(&m_Lock);}
	/** Unlock. For separating control. */
	void		WriteUnlock()	{FX_RWLock_WriteUnlock(&m_Lock);}

protected:
	/** Critical section. */
	FX_RWLOCK	m_Lock;
	friend class CFX_RWLock;
};

class CFX_RWLock
{
public:
	CFX_RWLock() : m_pRWLock(NULL), m_nStatus(0) {}
	CFX_RWLock(FX_RWLOCK* pRWLock, FX_INT32 nStatus)
	{
		Init(pRWLock, nStatus);
	}
	CFX_RWLock(CFX_RWLockObject* pRWLockObj, FX_INT32 nStatus)
	{
		Init(&pRWLockObj->m_Lock, nStatus);
	}
	~CFX_RWLock()
	{
		if (!m_pRWLock || !m_nStatus) return;
		if (m_nStatus < 0)
			FX_RWLock_ReadUnlock(m_pRWLock);
		else
			FX_RWLock_WriteUnlock(m_pRWLock);
	}

	/** Try to lock for share read. For separating control. */
	FX_BOOL		TryReadLock()
	{
		if (FX_RWLock_TryReadLock(m_pRWLock))
		{
			m_nStatus = -1;
			return TRUE;
		}
		return FALSE;
	}
	/** Lock for share read. For separating control. */
	void		ReadLock()
	{
		FX_RWLock_ReadLock(m_pRWLock);
		m_nStatus = -1;
	}
	/** Unlock for share read. For separating control. */
	void		ReadUnlock()
	{
		m_nStatus = 0;
		FX_RWLock_ReadUnlock(m_pRWLock);
	}
	/** Try to lock for exclusive write. For separating control. */
	FX_BOOL		TryWriteLock()
	{
		if (FX_RWLock_TryWriteLock(m_pRWLock))
		{
			m_nStatus = 1;
			return TRUE;
		}
		return FALSE;
	}
	/** Lock for exclusive write. For separating control. */
	void		WriteLock()
	{
		FX_RWLock_WriteLock(m_pRWLock);
		m_nStatus = 1;
	}
	/** Unlock for exclusive write. For separating control. */
	void		WriteUnlock()
	{
		m_nStatus = 0;
		FX_RWLock_WriteUnlock(m_pRWLock);
	}

protected:
	FX_RWLOCK*	m_pRWLock;
	FX_INT32	m_nStatus;

	void	Init(FX_RWLOCK* pRWLock, FX_INT32 nStatus)
	{
		m_pRWLock = pRWLock, m_nStatus = nStatus;
		if (!m_pRWLock || !m_nStatus) return;
		if (m_nStatus < 0)
			FX_RWLock_ReadLock(m_pRWLock);
		else
			FX_RWLock_WriteLock(m_pRWLock);
	}
};

/** @brief A macro defines a lock operation with this pointer. */
#define FXMT_RWLOCK_THIS						CFX_RWLock _fx_rwlock((CFX_RWLock*)this)
/** @brief A macro defines a lock operation with a lock object and status. */
#define FXMT_RWLOCK_OBJ(lock, s)				CFX_RWLock _fx_rwlock(lock, s)
/** @brief A macro defines a named lock operation with a lock object. */
#define FXMT_RWLOCK_DEFINEOBJ(rwLock, lock, s)	CFX_RWLock rwLock(lock, s)

/** @brief A macro defines a lock object. */
#define FXMT_RWLOCKOBJECT_DEFINE(rwLockObj)		CFX_RWLockObject rwLockObj
/** @brief A macro tries to lock. */
#define FXMT_RWLOCKOBJECT_TRYREADLOCK(lockObj)	(lockObj)->TryReadLock()
/** @brief A macro tries to lock with if. */
#define FXMT_RWLOCKOBJECT_TRYREADLOCK_IF(lockObj)	if ((lockObj)->TryReadLock())
/** @brief A macro locks. */
#define FXMT_RWLOCKOBJECT_READLOCK(lockObj)		(lockObj)->ReadLock()
/** @brief A macro unlocks. */
#define FXMT_RWLOCKOBJECT_READUNLOCK(lockObj)		(lockObj)->ReadUnlock()
/** @brief A macro tries to lock. */
#define FXMT_RWLOCKOBJECT_TRYWRITELOCK(lockObj)	(lockObj)->TryWriteLock()
/** @brief A macro tries to lock with if. */
#define FXMT_RWLOCKOBJECT_TRYWRITELOCK_IF(lockObj)	if ((lockObj)->TryWriteLock())
/** @brief A macro locks. */
#define FXMT_RWLOCKOBJECT_WRITELOCK(lockObj)		(lockObj)->WriteLock()
/** @brief A macro unlocks. */
#define FXMT_RWLOCKOBJECT_WRITEUNLOCK(lockObj)		(lockObj)->WriteUnlock()
#else

/** @brief	Under non-threading mode, defines as empty implementation. */
class CFX_RWLock {};
#define FXMT_RWLOCK_THIS
#define FXMT_RWLOCK_OBJ(lock, s)
#define FXMT_RWLOCK_DEFINEOBJ(rwLock, lock, s)

#define FXMT_RWLOCKOBJECT_DEFINE(rwLockObj)
#define FXMT_RWLOCKOBJECT_TRYREADLOCK(lockObj)
#define FXMT_RWLOCKOBJECT_TRYREADLOCK_IF(lockObj)
#define FXMT_RWLOCKOBJECT_READLOCK(lockObj)
#define FXMT_RWLOCKOBJECT_READUNLOCK(lockObj)
#define FXMT_RWLOCKOBJECT_TRYWRITELOCK(lockObj)
#define FXMT_RWLOCKOBJECT_TRYWRITELOCK_IF(lockObj)
#define FXMT_RWLOCKOBJECT_WRITELOCK(lockObj)
#define FXMT_RWLOCKOBJECT_WRITEUNLOCK(lockObj)
#endif

/*@}*/

//*****************************************************************************
//* Atomic Count
//*****************************************************************************
/**
 * @name Atomic Count
 *
 * @remark	Atomic Count provides an atomic mechanism to access integer value between multiple threads.
 *			Following functions also work under single-thread mode.
 */
/*@{*/

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief	Increase 32-bits integer value.
 *
 * @param[in,out] pAddend	Pointer to 32-bits integer to increase value.
 * @param[in] nIncrement	Increment value to be added to pAddend.
 *
 * @return	New increment value.
 */
FX_INT32	FX_Atom_Add32(volatile FX_INT32* pAddend, FX_INT32 nIncrement);
/**
 * @brief	Decrease 32-bits integer value.
 *
 * @param[in,out] pAddend	Pointer to 32-bits integer to decrease value.
 * @param[in] nDecrement	Decrement value to be subtracted from pAddend.
 *
 * @return	New decrement value.
 */
FX_INT32	FX_Atom_Subtract32(volatile FX_INT32* pAddend, FX_INT32 nDecrement);
/**
 * @brief	Increase 64-bits integer value.
 *
 * @param[in,out] pAddend	Pointer to 64-bits integer to increase value.
 * @param[in] nIncrement	Increment value to be added to pAddend.
 *
 * @return	New increment value.
 */
FX_INT64	FX_Atom_Add64(volatile FX_INT64* pAddend, FX_INT64 nIncrement);
/**
 * @brief	Decrease 64-bits integer value.
 *
 * @param[in,out] pAddend	Pointer to 64-bits integer to decrease value.
 * @param[in] nDecrement	Decrement value to be subtracted from pAddend.
 *
 * @return	New decrement value.
 */
FX_INT64	FX_Atom_Subtract64(volatile FX_INT64* pAddend, FX_INT64 nDecrement);

#ifdef __cplusplus
}
#endif

/*@}*/

#endif	/* _FX_PROCESS_H_ */

#endif //_FXM_OPENSOURCE_

/** @} */
